package desktop.agent;


import java.net.URL;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.swing.JOptionPane;
import javax.xml.namespace.QName;

import org.xmlsoap.schemas.ws._2003._03.addressing.EndpointReferenceType;

import com.nortel.soa.oi.cct.agentservice.AgentService;
import com.nortel.soa.oi.cct.agentservice.SOAOICCTAgentService;
import com.nortel.soa.oi.cct.contactservice.ContactService;
import com.nortel.soa.oi.cct.contactservice.SOAOICCTContactService;
import com.nortel.soa.oi.cct.sessionservice.AnswerContactException;
import com.nortel.soa.oi.cct.sessionservice.DropContactException;
import com.nortel.soa.oi.cct.sessionservice.GetIntrinsicsException;
import com.nortel.soa.oi.cct.sessionservice.GetReadyStateException;
import com.nortel.soa.oi.cct.sessionservice.GetTerminalsException;
import com.nortel.soa.oi.cct.sessionservice.GetVersionException;
import com.nortel.soa.oi.cct.sessionservice.LoginAgentException;
import com.nortel.soa.oi.cct.sessionservice.LogoutAgentException;
import com.nortel.soa.oi.cct.sessionservice.SOAOICCT;
import com.nortel.soa.oi.cct.sessionservice.SessionNotCreatedException;
import com.nortel.soa.oi.cct.sessionservice.SessionService;
import com.nortel.soa.oi.cct.sessionservice.SetToNotReadyStateException;
import com.nortel.soa.oi.cct.sessionservice.SetToReadyStateException;
import com.nortel.soa.oi.cct.types.Agent;
import com.nortel.soa.oi.cct.types.AgentReadyStatus;
import com.nortel.soa.oi.cct.types.AgentType;
import com.nortel.soa.oi.cct.types.AuthenticationLevel;
import com.nortel.soa.oi.cct.types.Contact;
import com.nortel.soa.oi.cct.types.Intrinsic;
import com.nortel.soa.oi.cct.types.SsoToken;
import com.nortel.soa.oi.cct.types.Terminal;
import com.nortel.soa.oi.cct.types.agentservice.AgentRequest;
import com.nortel.soa.oi.cct.types.agentservice.LoginRequest;
import com.nortel.soa.oi.cct.types.contactservice.ContactRequest;
import com.nortel.soa.oi.cct.types.contactservice.GetIntrinsicsResponse;


import com.nortel.soa.oi.cct.types.sessionservice.GetReadyStateResponse;
import com.nortel.soa.oi.cct.types.sessionservice.GetTerminalsRequest;
import com.nortel.soa.oi.cct.types.sessionservice.LogInToCCTServerRequest;
import com.nortel.soa.oi.cct.types.sessionservice.LogInToCCTServerResponse;
import com.nortel.soa.oi.cct.types.sessionservice.LoginAgentRequest;
import com.nortel.soa.oi.cct.types.sessionservice.LogoutAgentRequest;
import com.nortel.soa.oi.cct.types.sessionservice.TerminalContactRequest;
import com.nortel.soa.oi.cct.types.sessionservice.TerminalList;
import com.nortel.soa.oi.cct.types.sessionservice.TerminalRequest;

/**
 *
 * @author SMYJOE
 */


public class ServiceUtil {
	private static final QName SERVICE_NAME = new QName("http://www.nortel.com/soa/oi/cct/SessionService", "SOAOICCT");
	private static final QName AGENT_SERVICE_NAME = new QName("http://www.nortel.com/soa/oi/cct/AgentService", "SOAOICCT_AgentService");
	private static final QName CONTACT_SERVICE_NAME = new QName("http://www.nortel.com/soa/oi/cct/ContactService", "SOAOICCT_ContactService");
 

	SessionService sessionService = null;
	String cctServer = null;
	String agentName = null;
	String password = null;
	String domainName = null;
	String phonsetName = null;
	String phonesetPassword = null;
	SsoToken ssoToken = null;
	Terminal terminal = null;
	Contact contact = null;
	private EndpointReferenceType subscriptionRef;

	public static boolean TWITTER_CLOSE = false;

	private Object lock = new Object();


	private AgentService agentService;
	private ContactService contactService;

	public ServiceUtil(String cctServer, String agentName, String password, String domainName){
		this.cctServer = cctServer;
		this.agentName = agentName;
		this.password = password;
		this.domainName = domainName;
		getSessionService();
		getAgentService();

	}

	public Contact getContact() {
		return contact;
	}

	public String getIntrinsic(String key){
		String value = null;

		try {
			List<Intrinsic> intrinsics = getIntrinsics();
			if(intrinsics != null){
				for(Intrinsic intrinsic : intrinsics) {
					if(intrinsic.getKey().equalsIgnoreCase(key)){
						value = intrinsic.getValue();
					}
				}
			}

		} catch (Exception ex) {
			Logger.getLogger(ServiceUtil.class.getName()).log(Level.SEVERE, null, ex);
		}
		return value;
	}

	public void setContact(Contact contact) {
		this.contact = contact;
	}


	private SessionService getSessionService(){
		try {
			if(sessionService == null || ssoToken == null){

				URL wsdlURL = new URL("http://" + cctServer + "/SOAOICCT/services/SessionService?wsdl");
				System.err.println("wsdl_url" + "http://" + cctServer + "/SOAOICCT/services/SessionService?wsdl");

				SOAOICCT ss = new SOAOICCT(wsdlURL, SERVICE_NAME);
				sessionService = ss.getSessionService();

				LogInToCCTServerRequest loginToCctRequest = new LogInToCCTServerRequest();
				loginToCctRequest.setAuthenticationLevel(new AuthenticationLevel());
				loginToCctRequest.getAuthenticationLevel().setDomain(domainName);
				loginToCctRequest.getAuthenticationLevel().setPassword(password);
				loginToCctRequest.getAuthenticationLevel().setUsername(agentName);
				LogInToCCTServerResponse response = sessionService.logInToCCTServer(loginToCctRequest);
				ssoToken= response.getSsoToken();

				List<Terminal> terminals = getTerminals();
				getTerminal(terminals);



			}
		} catch (Exception ex) {
			Logger.getLogger(ServiceUtil.class.getName()).log(Level.SEVERE, null, ex);
			JOptionPane.showMessageDialog(null, "Error connecting/logging in to CCT Server. [" + ex.getMessage() + "]");
		}

		return sessionService;

	}

	
	
	private AgentService getAgentService(){
		try {
			if(agentService == null || ssoToken == null){

				URL wsdlURL = new URL("http://" + cctServer + "/SOAOICCT/services/AgentService?wsdl");
				System.err.println("wsdl_url" + "http://" + cctServer + "/SOAOICCT/services/AgentService?wsdl");

				SOAOICCTAgentService ss = new SOAOICCTAgentService(wsdlURL, AGENT_SERVICE_NAME);
				agentService = ss.getAgentService();

			}
		} catch (Exception ex) {
			Logger.getLogger(ServiceUtil.class.getName()).log(Level.SEVERE, null, ex);
			JOptionPane.showMessageDialog(null, "Error connecting/logging in to CCT Server. [" + ex.getMessage() + "]");
		}

		return agentService;

	}

	private ContactService getContactService(){
		try {
			if(contactService == null || ssoToken == null){

				URL wsdlURL = new URL("http://" + cctServer + "/SOAOICCT/services/ContactService?wsdl");
				System.err.println("wsdl_url" + "http://" + cctServer + "/SOAOICCT/services/ContactService?wsdl");

				SOAOICCTContactService ss = new SOAOICCTContactService(wsdlURL, CONTACT_SERVICE_NAME);
				contactService = ss.getContactService();

			}
		} catch (Exception ex) {
			Logger.getLogger(ServiceUtil.class.getName()).log(Level.SEVERE, null, ex);
			JOptionPane.showMessageDialog(null, "Error connecting/logging in to CCT Server. [" + ex.getMessage() + "]");
		}

		return contactService;

	}

	public String getVersion(){
		String version = null;

		try {

			com.nortel.soa.oi.cct.types.GetVersionRequest request = null;
			com.nortel.soa.oi.cct.types.GetVersionResponse response =  getSessionService().getVersion(request);

			if(version != null){
				version = response.getVersion();

			}
			Logger.getLogger(ServiceUtil.class.getName()).log(Level.INFO, "getVersion.result = " + version);

		} catch (SessionNotCreatedException ex) {
			Logger.getLogger(ServiceUtil.class.getName()).log(Level.SEVERE, null, ex);
		} catch (GetVersionException ex) {
			Logger.getLogger(ServiceUtil.class.getName()).log(Level.SEVERE, null, ex);
		}


		return version;
	}

	public void loginAgent(String phonsetName, String phonesetPassword){
		//loginAgentResult(phonsetName, phonesetPassword);
		loginAgentAS(phonsetName, phonesetPassword);
	}

	public boolean loginAgentAS(String phonsetName2, String phonesetPassword2) {
		boolean ok = true;
		try {
			LoginRequest request = new LoginRequest();
			request.setSsoToken(ssoToken);
			request.setPassword(phonesetPassword2);
			//request.setInitialState(AgentReadyStatus.READY);
			request.setIntialState(2);  //1 - not ready, 2 =  ready
			Agent agent = new Agent();
			agent.setAgentLoginId(phonsetName2);
			agent.setUserName(this.agentName);
			agent.setAgentType(AgentType.AGENT);
			 
			
			
			request.setAgent(agent);
			
			
			getAgentService().login(request);
			
		} catch (Exception e) {
			if (e.getMessage() != null && e.getMessage().contains("the agent is in the wrong status to perform the capability:Login")) {
				//agent already logged in;
				return ok;
			}
			Logger.getLogger(ServiceUtil.class.getName()).log(Level.SEVERE, null, e);
			ok = false;
		}
		return ok;
		
	}

	 

	public boolean loginAgentResult(String phonsetName, String phonesetPassword){
		boolean ok = false;
		synchronized (lock) {

			try{
				checkTerminal();

				LoginAgentRequest request = new LoginAgentRequest();
				request.setSsoToken(ssoToken);
				request.setAgentId(phonsetName);
				request.setAgentPassword(phonesetPassword);
				request.setTerminal(getTerminal(getTerminals()));
				getSessionService().loginAgent(request);

				ok = true;

			} catch (LoginAgentException ex) {
				//if terminal is active - implies agent is already logged in
				if (ex.getMessage().contains("AgentTerminal parameter must only be passive.AgentTerminal")) {
					ok = true;

				} else if (ex.getMessage().contains("the agent is in the wrong status to perform the capability:Login")) {
					//User is already logged in
					ok = true;
				} else {
					Logger.getLogger(ServiceUtil.class.getName()).log(Level.SEVERE, null, ex);
				}
			} catch (SessionNotCreatedException ex) {
				Logger.getLogger(ServiceUtil.class.getName()).log(Level.SEVERE, null, ex);
				ok = false;
			} catch (Exception ex) {
				Logger.getLogger(ServiceUtil.class.getName()).log(Level.SEVERE, null, ex);
				ok = false;
			}

		}
		return ok;
	}

	private Terminal getTerminal(List<Terminal> terminals) {
		if (terminals == null || terminals.isEmpty()) {
			terminal = null;
		} else {
			for (Terminal t : terminals) {
				if (t != null) {
					Logger.getLogger(ServiceUtil.class.getName()).log(Level.INFO, "terminalName = " + t.getTerminalName());
				}
				if (t.getTerminalName() != null && t.getTerminalName().startsWith("DefaultNode_") ){
					terminal = t;
					return terminal;
					
				}
				
//				if (t  != null
//						&& t.getProvider() != null
//						&& "ACTIVE".equalsIgnoreCase(t.getProvider().getProviderName())) {
//					terminal = t;
//					return terminal;
//				} 
			}
			if (terminal == null) {
				terminal = terminals.get(0);
			}
			
			Logger.getLogger(ServiceUtil.class.getName()).log(Level.INFO, "terminalName = " + terminal.getTerminalName());
		}

		return terminal;
	}

	private List<Terminal> getTerminals() throws SessionNotCreatedException,
	GetTerminalsException {
		GetTerminalsRequest getTerminalsRequest = new GetTerminalsRequest();
		getTerminalsRequest.setSsoToken(ssoToken);
		TerminalList terminalsList = sessionService.getTerminals(getTerminalsRequest);
		List<Terminal> terminals = terminalsList.getTerminals();
		return terminals;
		
	}

	public void logoutAgent(){

		synchronized (lock) {

			checkTerminal();
			try{

				LogoutAgentRequest request = new LogoutAgentRequest();
				request.setSsoToken(ssoToken);
				request.setTerminal(terminal);
				getSessionService().logoutAgent(request);
				terminal = null;

			} catch (LogoutAgentException ex) {
				Logger.getLogger(ServiceUtil.class.getName()).log(Level.SEVERE, null, ex);
			} catch (Exception ex) {
				Logger.getLogger(ServiceUtil.class.getName()).log(Level.SEVERE, null, ex);
			} 
		}
	}

	private void checkTerminal() {
		try {
			terminal = getTerminal(getTerminals());
			Logger.getLogger(ServiceUtil.class.getName()).log(Level.SEVERE, "terminal set ok.");
		} catch (Exception e) {
			Logger.getLogger(ServiceUtil.class.getName()).log(Level.SEVERE, null, e);
		}
	}
	
	
	public boolean isReady(){
		checkTerminal();

		if (terminal == null) {
			Logger.getLogger(ServiceUtil.class.getName()).log(Level.SEVERE, "terminal null - hence not ready.");
			return false;
		}

		boolean result = false;
		try {

			TerminalRequest request = new TerminalRequest();
			request.setSsoToken(ssoToken);
			request.setTerminal(terminal);
			GetReadyStateResponse response =  getSessionService().getReadyState(request);
			if(response != null){
				result = response.isReady();
			}
			
		} catch (GetReadyStateException ex) {
			Logger.getLogger(ServiceUtil.class.getName()).log(Level.SEVERE, null, ex);
		} catch (SessionNotCreatedException ex) {
			Logger.getLogger(ServiceUtil.class.getName()).log(Level.SEVERE, null, ex);
		}
		Logger.getLogger(ServiceUtil.class.getName()).log(Level.SEVERE, "isReady = " + result);
		return result;
	}



	public void setReadyStatus(boolean isReady){
		Logger.getLogger(ServiceUtil.class.getName()).log(Level.SEVERE, "setReadyStatus " + isReady);

		checkTerminal();
		if (terminal == null) {
			Logger.getLogger(ServiceUtil.class.getName()).log(Level.SEVERE, "Cannot set ready status on null terminal");
			return;
		}

		TerminalRequest request = new TerminalRequest();
		request.setSsoToken(ssoToken);
		request.setTerminal(terminal);

		try {
			if(isReady){

				getSessionService().setToReadyState(request);

			}else{ 

				getSessionService().setToNotReadyState(request);
				if(contact != null){
					drop();
				}

			}
		} catch (SetToReadyStateException ex) {
			Logger.getLogger(ServiceUtil.class.getName()).log(Level.SEVERE, null, ex);
		} catch (SessionNotCreatedException ex) {
			Logger.getLogger(ServiceUtil.class.getName()).log(Level.SEVERE, null, ex);
		} catch (SetToNotReadyStateException ex) {
			Logger.getLogger(ServiceUtil.class.getName()).log(Level.SEVERE, null, ex);
		}catch (Exception ex) {
			Logger.getLogger(ServiceUtil.class.getName()).log(Level.SEVERE, null, ex);
		}
	}

	public boolean getReadyStatus(){

		checkTerminal(); 
		if (terminal == null) {
			return false;
		}
		TerminalRequest request = new TerminalRequest();
		request.setSsoToken(ssoToken);
		request.setTerminal(terminal);


		System.out.println("terminal status = " + terminal.getStatus());

		try {

			GetReadyStateResponse response = getSessionService().getReadyState(request);
			return response.isReady();

		} catch (Exception ex) {
			Logger.getLogger(ServiceUtil.class.getName()).log(Level.SEVERE, null, ex);
			return false;
		}
	}

	public void accept(){
		try {
			if(this.contact !=null){
				//if (terminal == null) {
					checkTerminal();
				//}
					
					Logger.getLogger(ServiceUtil.class.getName()).log(Level.SEVERE, "" + terminal.getTerminalName());	
					
				TerminalContactRequest request = new TerminalContactRequest();
				request.setSsoToken(ssoToken);
				request.setTerminal(terminal);
				request.setContact(contact);

				getSessionService().answerContact(request);

			}

		} catch (AnswerContactException ex) {
			Logger.getLogger(ServiceUtil.class.getName()).log(Level.SEVERE, null, ex);
		} catch (SessionNotCreatedException ex) {
			Logger.getLogger(ServiceUtil.class.getName()).log(Level.SEVERE, null, ex);
		}
	}

	public void drop(){
		try {

			if(this.contact !=null){
				TerminalContactRequest request = new TerminalContactRequest();
				request.setSsoToken(ssoToken);
				request.setTerminal(terminal);
				request.setContact(contact);

				getSessionService().dropContact(request);
				this.contact = null;

			}

		} catch (DropContactException ex) {
			Logger.getLogger(ServiceUtil.class.getName()).log(Level.SEVERE, null, ex);
		} catch (SessionNotCreatedException ex) {
			Logger.getLogger(ServiceUtil.class.getName()).log(Level.SEVERE, null, ex);
		}
	}

	public void addListener(OICCADNotificationListener listener){

		try {
			SubscribeUtil.publishNotificationConsumer(listener, this);
			subscriptionRef = SubscribeUtil.subscribe(ssoToken, cctServer);

		} catch (Exception ex) {
			Logger.getLogger(ServiceUtil.class.getName()).log(Level.SEVERE, null, ex);
			JOptionPane.showMessageDialog(null, "Warning Address is in use no alerts!");

		}
	}

	public void unsubscribe() {
		Logger.getLogger(ServiceUtil.class.getName()).log(Level.INFO, "Unsubscribing");
		try {
			if (subscriptionRef != null) {
				SubscribeUtil.unsubscribe(ssoToken, subscriptionRef);
			}
		} catch (Exception ex) {
			Logger.getLogger(ServiceUtil.class.getName()).log(Level.SEVERE, null, ex);
		}
	}

	public String getIntrinsicsMessage() {
		List<Intrinsic> intrinsics = getIntrinsics();
		if (intrinsics == null) {
			return "";
		} 
		StringBuffer buff = new StringBuffer();
		for(Intrinsic intrinsic : intrinsics) {
			if (!"Provider".equalsIgnoreCase(intrinsic.getKey()) 
					&& ! "Skillset".equalsIgnoreCase(intrinsic.getKey()) ){
				buff.append(intrinsic.getKey() + " : " + intrinsic.getValue() + "\n");
			}
		}
		return buff.toString();
	}

//	private List<Intrinsic> getIntrinsicsSS() {
//		if (contact == null) {
//			return null;
//		}
//		ContactRequest request = new ContactRequest();
//		request.setContact(contact);
//		request.setSsoToken(ssoToken);
//		GetIntrinsicsResponse response = null;
//		try {
//			response = getSessionService().getIntrinsics(request);
//		} catch (SessionNotCreatedException e) {
//			Logger.getLogger(ServiceUtil.class.getName()).log(Level.SEVERE, null, e);
//		} catch (GetIntrinsicsException e) {
//			Logger.getLogger(ServiceUtil.class.getName()).log(Level.SEVERE, null, e);
//		}
//		if(response != null){
//			return response.getIntrinsic();
//		}
//		return null;
//
//
//	}

	
	private List<Intrinsic> getIntrinsics() {
		if (contact == null) {
			return null;
		}
		ContactRequest request = new ContactRequest();
		request.setContact(contact);
		request.setSsoToken(ssoToken);
		 GetIntrinsicsResponse response = null;
		
		try {
			
			
			response = getContactService().getIntrinsics(request);//.getIntrinsics(request);
		} catch (Exception e) {
			Logger.getLogger(ServiceUtil.class.getName()).log(Level.SEVERE, null, e);
		}if(response != null){
			return response.getIntrinsic();
		}
		return null;


	}

	
}
